#!/usr/bin/env python
"""
verifypkg

Takes a signed .ubiq file as input and returns True if the verifcation 
succeeds and false otherwise.
"""

__author__ = 'Matt Kemp <mkemp2@cct.lsu.edu>'
__version__ = 'verifypkg v0.2 6-14-06'

import anydbm
import sys
import urllib2
import xml.etree.ElementTree as ET
from base64 import b64decode
from hashlib import sha1
from optparse import OptionParser

from Crypto.Util import number

from ubiqis import keytool
from ubiqis import names

trusted_keys = anydbm.open('trusted.db','c')

def keycheck(host, key, name):
  def foundkey(loc):
    if opts.debug:
      sys.stdout.write('Debug: Found matching key from: %s\n' % loc)
    return True

  if trusted_keys.has_key(host) and trusted_keys[host] == key:
    return foundkey('Local Cache')
  else: 
    url = 'http://%s/getkey' % host
    try:
      temp = urllib2.urlopen(url).read()
    except urllib2.URLError:
      url = 'http://%s/signpkg?url=%s' % (host, names.pkg2url(name))
      try:
        temp = urllib2.urlopen(url).read()
      except urllib2.URLError, msg:
        sys.stdout.write("Error, can't verify key.\n%s\n" % msg)
      else:
        tree = ET.fromstring(temp)
        sigs = tree.findall('signature')
        for sig in sigs:
          if sig.findtext('public-key') == key:
            trusted_keys[host] = key
            return foundkey(url)
        return False
    else:
      if temp == key:
        trusted_keys[host] = key
        return foundkey(url)

def verify(ubiq):
  """Verifies a .ubiq file from a string form of XML"""

  # Create a tree from the XML input.
  tree = ET.fromstring(ubiq)
  name = tree.findtext('name')
  signatures = tree.findall('signature')
  # Separate the signature(s) from the original .ubiq
  for sig in signatures:
    tree.remove(sig)
  # Recreate hash used in signing
  orig_hash = sha1()
  orig_hash.update(''.join(ET.tostring(tree).split()))
  verified = []
  for signature in signatures:
    host = signature.findtext('host')
    pub_key = signature.findtext('public-key')
    if keycheck(host, pub_key, name):
      pub_key = keytool.key_from_string(b64decode(pub_key))
      # Recreate signature data in tuplized, long form
      sig_data = b64decode(signature.findtext('signed-data'))
      sig_data = (number.bytes_to_long(sig_data),)
      # Generate the public key object
      if pub_key.verify(orig_hash.hexdigest(), sig_data):
        verified.append('Success')

  if verified:
    return True
  else:
    return False
if __name__ == "__main__":

  usage = 'usage: %prog [options] <url_to_ubiq_file>'
  parser = OptionParser(version=__version__)
  parser.set_usage(usage)
  parser.add_option('-f', '--file', dest='filename',
                    help='use FILE as input', metavar='FILE')
  parser.add_option('-d', '--debug', dest='debug', action='store_true',
                    help='print debugging output', default=False)
      
  opts, args = parser.parse_args()

  if opts.filename:
    infile = open(opts.filename,'r')
  else:
    infile = sys.stdin

  if verify(infile.read()):
    print 'Success'
  else:
    print 'Failure'

  infile.close()
